package cn.itcast.nems.manager.auth;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.Base64;
import java.util.concurrent.TimeUnit;

/**
 * keycloak
 *
 * @author liyong
 */
public class KeycloakHelper {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private static final OkHttpClient httpClient = new OkHttpClient.Builder()
            .connectTimeout(60, TimeUnit.SECONDS)
            .readTimeout(60, TimeUnit.SECONDS)
            .writeTimeout(60, TimeUnit.SECONDS).build();

    private KCAccessToken accessToken;
    private final ObjectMapper objectMapper;
    private final KeycloakConfig keycloakConfig;

    public KeycloakHelper(KeycloakConfig keycloakConfig) {
        this.keycloakConfig = keycloakConfig;
        this.objectMapper = new ObjectMapper();
    }

    public String getAccessToken() {
        if (accessToken == null || !accessToken.isValid()) {
            this.createAccessToken();
        }
        return this.accessToken.getToken();
    }

    private synchronized void createAccessToken() {
        try {
            final String res = this.sendHttpRequest();
            final JsonNode json = objectMapper.readTree(res);
            if (json.has("error")) {
                final String error = json.get("error").asText();
                final String errorDesc = json.get("error_description").asText();
                throw new RuntimeException("error:" + error + ", error_description:" + errorDesc);
            }
            String token = json.path("access_token").asText();
            int expiresIn = json.path("expires_in").asInt();
            this.accessToken = new KCAccessToken(token, expiresIn);
        } catch (Exception e) {
            String msg = "获取token失败:'" + this.keycloakConfig.kcTokenUrl() + "'";
            logger.info(msg);
            throw new RuntimeException(msg + e.getMessage(), e);
        }
    }

    private String sendHttpRequest() throws IOException {
        FormBody form = new FormBody.Builder()
                .add("grant_type", "client_credentials")
                .build();
        String auth = this.keycloakConfig.kcClientId() + ":" + this.keycloakConfig.kcSecret();
        auth = Base64.getEncoder().encodeToString(auth.getBytes());
        Request request = new Request.Builder()
                .addHeader("Authorization", "Basic " + auth)
                .addHeader("Content-Type", "application/x-www-form-urlencoded")
                .url(this.keycloakConfig.kcTokenUrl())
                .post(form)
                .build();
        try (Response response = httpClient.newCall(request).execute()) {
            final ResponseBody body = response.body();
            return body != null ? body.string() : "";
        }
    }
}